package debug

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"strings"
	"time"
)

func Line() (str string) {
	var name, file string
	var line int
	var pc [16]uintptr

	n := runtime.Callers(5, pc[:])
	for _, pc := range pc[:n] {
		fn := runtime.FuncForPC(pc)
		if fn == nil {
			continue
		}
		file, line = fn.FileLine(pc)
		name = fn.Name()
		if !strings.HasPrefix(name, "runtime.") {
			break
		}
	}

	switch {
	case name != "":
		str = fmt.Sprintf("%v:%v", name, line)
	case file != "":
		str = fmt.Sprintf("%v:%v", file, line)
	default:
		str = fmt.Sprintf("pc:%x", pc)
	}

	return
}

func WriteStackTraceFile(p any, dir string) {
	content := fmt.Sprintf("%v\n\n%v\n\n%s", p, Line(), debug.Stack())
	filePath := fmt.Sprintf("stacktrace.%s.txt", time.Now().Format("20060102150405"))
	if dir != "" {
		filePath = filepath.Join(dir, filePath)
	}
	if err := os.WriteFile(filePath, []byte(content), 0777); err != nil {
		log.Panicf("write stack trace file fail, %s\n%s", err, content)
	}
}
